GMaps.prototype.drawOverlay = function (options) {
    var overlay = new google.maps.OverlayView(),
        auto_show = true;

    overlay.setMap(this.map);

    if (options.auto_show != null) {
        auto_show = options.auto_show;
    }

    overlay.onAdd = function () {
        var el = document.createElement('div');

        el.style.borderStyle = "none";
        el.style.borderWidth = "0px";
        el.style.position = "absolute";
        el.style.zIndex = 100;
        el.innerHTML = options.content;

        overlay.el = el;

        if (!options.layer) {
            options.layer = 'overlayLayer';
        }

        var panes = this.getPanes(),
            overlayLayer = panes[options.layer],
            stop_overlay_events = ['contextmenu', 'DOMMouseScroll', 'dblclick', 'mousedown'];

        overlayLayer.appendChild(el);

        for (var ev = 0; ev < stop_overlay_events.length; ev++) {
            (function (object, name) {
                google.maps.event.addDomListener(object, name, function (e) {
                    if (navigator.userAgent.toLowerCase().indexOf('msie') != -1 && document.all) {
                        e.cancelBubble = true;
                        e.returnValue = false;
                    } else {
                        e.stopPropagation();
                    }
                });
            })(el, stop_overlay_events[ev]);
        }

        if (options.click) {
            panes.overlayMouseTarget.appendChild(overlay.el);
            google.maps.event.addDomListener(overlay.el, 'click', function () {
                options.click.apply(overlay, [overlay]);
            });
        }

        google.maps.event.trigger(this, 'ready');
    };

    overlay.draw = function () {
        var projection = this.getProjection(),
            pixel = projection.fromLatLngToDivPixel(new google.maps.LatLng(options.lat, options.lng));

        options.horizontalOffset = options.horizontalOffset || 0;
        options.verticalOffset = options.verticalOffset || 0;

        var el = overlay.el,
            content = el.children[0],
            content_height = content.clientHeight,
            content_width = content.clientWidth;

        switch (options.verticalAlign) {
            case 'top':
                el.style.top = (pixel.y - content_height + options.verticalOffset) + 'px';
                break;
            default:
            case 'middle':
                el.style.top = (pixel.y - (content_height / 2) + options.verticalOffset) + 'px';
                break;
            case 'bottom':
                el.style.top = (pixel.y + options.verticalOffset) + 'px';
                break;
        }

        switch (options.horizontalAlign) {
            case 'left':
                el.style.left = (pixel.x - content_width + options.horizontalOffset) + 'px';
                break;
            default:
            case 'center':
                el.style.left = (pixel.x - (content_width / 2) + options.horizontalOffset) + 'px';
                break;
            case 'right':
                el.style.left = (pixel.x + options.horizontalOffset) + 'px';
                break;
        }

        el.style.display = auto_show ? 'block' : 'none';

        if (!auto_show) {
            options.show.apply(this, [el]);
        }
    };

    overlay.onRemove = function () {
        var el = overlay.el;

        if (options.remove) {
            options.remove.apply(this, [el]);
        } else {
            overlay.el.parentNode.removeChild(overlay.el);
            overlay.el = null;
        }
    };

    this.overlays.push(overlay);
    return overlay;
};

GMaps.prototype.removeOverlay = function (overlay) {
    for (var i = 0; i < this.overlays.length; i++) {
        if (this.overlays[i] === overlay) {
            this.overlays[i].setMap(null);
            this.overlays.splice(i, 1);

            break;
        }
    }
};

GMaps.prototype.removeOverlays = function () {
    for (var i = 0, item; item = this.overlays[i]; i++) {
        item.setMap(null);
    }

    this.overlays = [];
};
